package cn.thr.ymcc.web.controller;

import cn.thr.ymcc.CourseDoc;
import cn.thr.ymcc.Query.CourseDocQuery;
import cn.thr.ymcc.repositmapp.HighlightResultMapper;
import cn.thr.ymcc.repository.CourseDocRepository;
import cn.thr.ymcc.result.JsonResult;
import cn.thr.ymcc.result.PageList;
import cn.thr.ymcc.vo.AggrPageList;
import cn.thr.ymcc.vo.AggrTermsBucket;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 全文检索服务接口
 * 批量新增/修改
 * 批量删除
 * 搜索
 *
 */
@RestController
@RequestMapping("/search")
public class SearchController  {

    @Autowired
    private CourseDocRepository courseDocRepository;

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Autowired
    private HighlightResultMapper highlightResultMapper;

    /**
     * 批量新增和修改
     * @param courseDocs
     * @return
     */
    @PostMapping("/saveBatch")
    public JsonResult saveBatch(@RequestBody List<CourseDoc> courseDocs){
        courseDocRepository.saveAll(courseDocs);
        return JsonResult.me();
    }

    /**
     * 批量删除
     * @param courseId
     * @return
     */
    @DeleteMapping("/deleteBatch")
    public JsonResult deleteBatch(@RequestBody List<Long> courseId){
        courseId.forEach(cid->courseDocRepository.deleteById(cid));
        return JsonResult.me();
    }

    /**
     * 从ES 索引库中去搜索课程数据
     * 支持高级查询+分页+排序
     * @param courseDocQuery
     * @return
     */
    @PostMapping("/queryCourse")
    public JsonResult queryCourse(@RequestBody CourseDocQuery courseDocQuery){
        //参数对象
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //工具类
        BoolQueryBuilder bool = QueryBuilders.boolQuery();

        //1.多个单分支语句动态添加搜索条件
        //如果Keyword是空的我就要添加数据
        if(StringUtils.hasText(courseDocQuery.getKeyword())){
            //要分词匹配QueryBuilders.matchQuery()   课程名称分词匹配
            bool.filter().add(QueryBuilders.matchQuery("name",courseDocQuery.getKeyword()));
        }

        if(courseDocQuery.getCourseTypeId() !=null){
            //精确匹配  不分词匹配  相当于数据库中的等于
            bool.filter().add(QueryBuilders.termQuery("courseTypeId",courseDocQuery.getCourseTypeId()));
        }

        if(StringUtils.hasText(courseDocQuery.getCourseTypeName())){
            //不分词
            bool.filter().add(QueryBuilders.termQuery("courseTypeName",courseDocQuery.getCourseTypeName()));
        }

        if(courseDocQuery.getGradeId() !=null){
            //精确匹配  不分词匹配  相当于数据库中的等于
            bool.filter().add(QueryBuilders.termQuery("gradeId",courseDocQuery.getGradeId()));
        }

        if(StringUtils.hasText(courseDocQuery.getGradeName())){
            //不分词
            bool.filter().add(QueryBuilders.termQuery("gradeName",courseDocQuery.getGradeName()));
        }
        if(courseDocQuery.getPriceMin() !=null){
            //范围匹配rangeQuery  gte()大于等于
            bool.filter().add(QueryBuilders.rangeQuery("price").gte(courseDocQuery.getPriceMin()));
        }
        if(courseDocQuery.getPriceMax() !=null){
            //范围匹配rangeQuery  lte小于等于
            bool.filter().add(QueryBuilders.rangeQuery("price").lte(courseDocQuery.getPriceMax()));
        }

        queryBuilder.withQuery(bool);

        //2.分页  queryBuilder.withPageable     SpringDataElasticsearch 分页页码是从0开始计算的
        queryBuilder.withPageable(PageRequest.of(courseDocQuery.getPageNo()-1,courseDocQuery.getPageSize()));

        //3.排序
        if(StringUtils.hasText(courseDocQuery.getOrderField())){
            //字段工具
            FieldSortBuilder sortBuilder = SortBuilders
                    .fieldSort(courseDocQuery.getOrderField())
                    //排序
                    .order(SortOrder.DESC);

            if("asc".equalsIgnoreCase(courseDocQuery.getOrderField())){
                sortBuilder.order(SortOrder.ASC);
            }
            queryBuilder.withSort(sortBuilder);
        }

        //4.添加关键字高亮，只能用在分词的字符串类型  加在执行前
        HighlightBuilder.Field  highlightField = new HighlightBuilder.Field("name")
                .preTags("<b style='color:red'>")
                .postTags("</b>");
        queryBuilder.withHighlightFields(highlightField);


        //5.添加聚合统计条件
        //聚合查询,按照课程等级名字聚合，按照数量倒排
        queryBuilder.addAggregation(AggregationBuilders
                .terms("gradeNameAgg") //聚合名字  起一个别名
                .field("gradeName.keyword")	//聚合的字段  以哪个字段进行分组
                .order(BucketOrder.count(false)).size(20));//排序后取前20条

        //聚合查询,按照课程等级名字聚合，按照数量倒排
        queryBuilder.addAggregation(AggregationBuilders
                .terms("courseTypeNameAgg") //聚合名字  起一个别名
                .field("courseTypeName.keyword")	//聚合的字段  以哪个字段进行分组
                .order(BucketOrder.count(false)).size(20));

        // 6.执行搜索
       // Page<CourseDoc> page = courseDocRepository.search(queryBuilder.build());

        AggregatedPage<CourseDoc> page = restTemplate.queryForPage(queryBuilder.build(), CourseDoc.class, highlightResultMapper);

        System.out.println("当前页码"+page.getNumber());
        System.out.println("每页条数"+page.getSize());
        System.out.println("总条数"+page.getTotalElements());
        System.out.println("总页数"+page.getTotalPages());
        System.out.println("当前页条数"+page.getNumberOfElements());

        //当前页的数据
        List<CourseDoc> content = page.getContent();


        //7.提取集合统计结果
        Map<String, List<AggrTermsBucket>> aggrMap = getAggrResult(page);

        //8.返回我们自己的palist
        AggrPageList<CourseDoc> pageList = new AggrPageList<>(page.getTotalElements(), content, aggrMap);

        return  JsonResult.me(pageList);
    }

    private Map<String, List<AggrTermsBucket>> getAggrResult(AggregatedPage<CourseDoc> page) {
        //用来封装聚合结果
        Map<String,List<AggrTermsBucket>> aggrMap = new HashMap<>();

        //遍历聚合结果
        Aggregations aggregations = page.getAggregations();

        Map<String, Aggregation> stringAggregationMap = aggregations.asMap();

        Set<Map.Entry<String, Aggregation>> entries = stringAggregationMap.entrySet();

        entries.forEach(e->{
            //集合的名字
            String key = e.getKey();
            //集合的值的处理
            ParsedStringTerms value = (ParsedStringTerms)e.getValue();
            List<? extends Terms.Bucket> buckets = value.getBuckets();

            //使用lomda 把  List<StringTerms.Bucket>  转成  List<AggrTermsVo>
            List<AggrTermsBucket> aggrTermsVos = buckets.stream().map(bucket -> {
                return new AggrTermsBucket(bucket.getKeyAsString(), bucket.getDocCount());
            }).collect(Collectors.toList());

            aggrMap.put(key, aggrTermsVos);
        });
        return aggrMap;
    }

    /**
     * 从订单确认页面发送请求，来查询课程数据
     * @param courseIds
     * @return
     */
    /**
     * 从订单确认页面发送请求，来查询课程数据
     * @param courseIds
     * @return
     */
    @PostMapping("/courseDocInfo")
    public JsonResult courseDocInfo(@RequestBody List<Long> courseIds){
        List<CourseDoc> courseDocs = (List<CourseDoc>) courseDocRepository.findAllById(courseIds);
        return JsonResult.me(courseDocs);
    }
}
